package gormdb

import (
	"errors"
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
	"strings"
	"time"
)

func defaultConfig() moreConfigEntry {
	return moreConfigEntry{
		MaxIdleConns:         20,
		MaxOpenConns:         256,
		ConnMaxLifetime:      60,
		RaiseErrorOnNotFound: false,
	}
}

func GenerateClient(config ConfigEntry, options ...OptFunc) (*gorm.DB, error) {
	dbOption := defaultConfig()
	for _, option := range options {
		option(&dbOption)
	}

	dialector, err := generateDialector(config)
	if err != nil {
		return nil, err
	}

	gormDB, err := gorm.Open(dialector, &gorm.Config{
		SkipDefaultTransaction: true,
		PrepareStmt:            true,
		Logger:                 logger.Default.LogMode(logger.Silent),
		NamingStrategy: schema.NamingStrategy{
			// 使用单数表名，启用该选项，此时，`User` 的表名应该是 `user`
			SingularTable: true,
		},
	})

	if err != nil {
		return nil, err
	}

	// 查询没有数据，屏蔽 gorm v2 包中会爆出的错误
	// https://github.com/go-gorm/gorm/issues/3789  此 issue 所反映的问题就是我们本次解决掉的
	gormDB.Callback().Query().Before("gorm:query").Register("disable_raise_record_not_found", func(db *gorm.DB) {
		db.Statement.RaiseErrorOnNotFound = dbOption.RaiseErrorOnNotFound
	})

	db, err := gormDB.DB()

	if err != nil {
		return nil, err
	}

	db.SetConnMaxIdleTime(30 * time.Second) //最大空闲时间
	db.SetMaxIdleConns(dbOption.MaxIdleConns)
	db.SetConnMaxLifetime(time.Duration(dbOption.ConnMaxLifetime) * time.Second)
	db.SetMaxOpenConns(dbOption.MaxOpenConns)

	return gormDB, nil

}

func generateDialector(config ConfigEntry) (gorm.Dialector, error) {
	var dbDialector gorm.Dialector

	switch strings.ToLower(config.DBType) {
	case "mysql":
		mysqlDsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local",
			config.Username,
			config.Password,
			config.Host,
			config.Port,
			config.DBName)
		dbDialector = mysql.Open(mysqlDsn)
	case "postgres", "postgresql", "postgre":
		postgresDsn := fmt.Sprintf("host=%s port=%d dbname=%s user=%s password=%s sslmode=disable TimeZone=Asia/Shanghai",
			config.Host,
			config.Port,
			config.DBName,
			config.Username,
			config.Password)
		dbDialector = postgres.Open(postgresDsn)
	default:
		return nil, errors.New("数据库驱动类型不存在,目前支持的数据库类型：mysql、sqlserver、postgresql，您提交数据库类型：" + config.DBType)
	}
	return dbDialector, nil
}
